package com.wr.client;

import com.alibaba.fastjson.JSON;
import com.wr.client.handler.UserClientHandler;
import com.wr.service.com.wr.request.RpcRequest;
import com.wr.service.com.wr.serializer.JSONSerializer;
import com.wr.service.com.wr.serializer.RpcEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * @author 王瑞
 * @description: TODO
 * @date 2020/3/21  20:18
 */
public class UserClient {

    private static int corePoolSize = 10;
    private static int maximumPoolSize = 50;
    private static long keepAliveTime = 100L;
    private static TimeUnit unit = TimeUnit.SECONDS;
    private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(50);//队列  默认50个
    private static ThreadFactory threadFactory = Executors.defaultThreadFactory();
    private static RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

    private static ThreadPoolExecutor poolExecutor =
            new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);

    private static UserClientHandler userClientHandler;


    //创建代理对象     conditionMethod: UserService#sayHello
    public Object createProxy(final Class<?> clazz) {
        Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("进入代理方法体");
               if (userClientHandler==null){
                   initClient();
               }
                String name = method.getName();

                RpcRequest rpcRequest = setParam(method, args);
                userClientHandler.setPara(rpcRequest);
               //当执行submit的时候 userClientHandler会执行call方法向服务端传递参数para  并进行等待  当服务端响应数据并返回的时候唤醒线程 返回结果 用过get方法获得结果
                System.out.println("方法："+name+"开始等待返回结果");
                Future submit = poolExecutor.submit(userClientHandler);
                Object o = submit.get();
                System.out.println("返回结果是："+o);
                return o;
            }
        });

        return proxyInstance;
    }

    /*封装RpcRequest实体*/
    public static RpcRequest setParam(Method method,Object[] args){
        RpcRequest rpcRequest = new RpcRequest();

        String methodName = method.getName();
        String className = method.getDeclaringClass().getName();

        Class<?>[] parameterTypes = method.getParameterTypes();

        rpcRequest.setParameterTypes(parameterTypes);
        String requestId = UUID.randomUUID().toString();
        rpcRequest.setClassName(className);
        rpcRequest.setMethodName(methodName);
        rpcRequest.setRequestId(requestId);
        rpcRequest.setParameters(args);

        return rpcRequest;
    }


    /*初始化客户端连接*/
    public static void initClient() throws InterruptedException {
        userClientHandler = new UserClientHandler();
        NioEventLoopGroup group = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new StringDecoder());   //设置解码器
                        pipeline.addLast(new RpcEncoder(RpcRequest.class,new JSONSerializer()));   //设置自定义编码器

                        pipeline.addLast(userClientHandler);     //主要的逻辑类
                    }
                });
        bootstrap.connect("127.0.0.1", 8888).sync();
    }

}
